package com.penglecode.nio.socket;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ServerHandler implements ConnectionHandler {

	private static final Log logger = LogFactory.getLog(ServerHandler.class);
	
	/**
	 * 默认读取/写入数据的buffer大小
	 */
	public static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
	
	/**
	 * 默认的数据缓冲区大小(单位字节)
	 */
	private int bufferSize;
	
	/**
	 * Selector对象，负责监控所有的连接到服务器的网络事件的发生
	 */
	private Selector selector;
	
	public ServerHandler(Selector selector) {
		super();
		this.bufferSize = DEFAULT_BUFFER_SIZE;
		this.selector = selector;
	}
	
	/**
	 * 处理客户端连接服务器事件
	 * @param selectionKey	-  服务器选择键对象
	 */
	public void handleConnect(SelectionKey selectionKey){
		SocketChannel client = null;
		try {
			ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
			client = server.accept();
			if(client == null){
				return;
			}
			client.configureBlocking(false); //将客户端Channel设置为非阻塞型
			//将客户端Channel注册到Selector对象上，并且指出客户端Channel所感兴趣的事件为可读和可写
			client.register(this.selector, SelectionKey.OP_READ);
			logger.debug("[Server] : a client connected to the server!");
		} catch (IOException e) {
			logger.error(e, e);
			IOUtils.closeQuietly(client);
		}
	}
	
	/**
	 * 进行读取客户端数据操作
	 * @param selectionKey	- 客户端选择键对象
	 */
	public void handleRead(SelectionKey selectionKey) {
		SocketChannel client = null;
		try {
			client = (SocketChannel) selectionKey.channel();
			/*//得到附件，就是上面handleServerSocketEvent方法中register方法调用的第三个输入参数
			ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();*/
			ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
			byte[] datas = BufferUtils.read(client, buffer);
			logger.debug(String.format("[Server] read message from client : %s", new String(datas, Charset.defaultCharset())));
			//从客户端读到了数据,下一步注册向客户端写数据事件
			//client.register(selector, SelectionKey.OP_WRITE, datas);
			selectionKey.interestOps(SelectionKey.OP_WRITE);
			selectionKey.attach(datas);
		} catch (Exception e) {
			logger.error(e, e);
			IOUtils.closeQuietly(client);
		}
	}
	
	/**
	 * 进行向客户端写数据操作
	 * @param selectionKey	- 客户端选择键对象
	 */
	public void handleWrite(SelectionKey selectionKey) {
		SocketChannel client = null;
		try {
			client = (SocketChannel) selectionKey.channel();
			byte[] datas = (byte[]) selectionKey.attachment();
			ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
			BufferUtils.write(client, buffer, datas);
			logger.debug(String.format("[Server] write message to client : %s", new String(datas, Charset.defaultCharset())));
			//触发向客户端读数据事件
			//client.register(selector, SelectionKey.OP_READ);
			selectionKey.interestOps(SelectionKey.OP_READ);
			selectionKey.attach(datas);
		} catch (Exception e) {
			logger.error(e, e);
			IOUtils.closeQuietly(client);
		}
	}
	
}
